#include "serialthread.h"
#include "iniconfig.h"

#include <QDebug>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>

SerialThread::SerialThread(QObject *parent) :
    QThread(parent)
{
    this->loop = false;                     // 初始化线程工作标志为false，表示尚未初始化
}

SerialThread::~SerialThread()
{
    this->loop = false;
    while(this->isRunning());
}

bool SerialThread::SerialOpenDevice(int &fd)
{
    fd = open(this->serialpath.toLatin1().data(), O_RDWR | O_NOCTTY | O_NDELAY);
    if(0 < fd)
    {
        qDebug() << "串口线程：打开设备文件成功，句柄为" << fd;
        if(0 == fcntl(fd, F_SETFL, 0))
        {
            qDebug() << "串口线程：成功设置句柄IO状态为阻塞";
            if(this->SerialSetOpt(fd))
            {
                qDebug() << "串口线程：成功设置句柄硬件参数";
                return true;
            }
            else
            {
                qDebug() << "串口线程：设置句柄硬件参数失败";
            }
        }
        else
        {
            qDebug() << "串口线程：设置句柄IO状态失败";
        }
    }
    else
    {
        qDebug() << "串口线程：打开设备失败";
    }
    return false;
}

bool SerialThread::SerialSetOpt(int fd)
{
    struct termios newtio;

    memset(&newtio, 0, sizeof(newtio));

    // 设置波特率
    switch(this->serialrate)
    {
    case 1200:
        cfsetispeed(&newtio, B1200);
        cfsetospeed(&newtio, B1200);
        break;
    case 1800:
        cfsetispeed(&newtio, B1800);
        cfsetospeed(&newtio, B1800);
        break;
    case 2400:
        cfsetispeed(&newtio, B2400);
        cfsetospeed(&newtio, B2400);
        break;
    case 4800:
        cfsetispeed(&newtio, B4800);
        cfsetospeed(&newtio, B4800);
        break;
    case 19200:
        cfsetispeed(&newtio, B19200);
        cfsetospeed(&newtio, B19200);
        break;
    case 38400:
        cfsetispeed(&newtio, B38400);
        cfsetospeed(&newtio, B38400);
        break;
    case 57600:
        cfsetispeed(&newtio, B57600);
        cfsetospeed(&newtio, B57600);
        break;
    case 115200:
        cfsetispeed(&newtio, B115200);
        cfsetospeed(&newtio, B115200);
        break;
    case 9600:                              // 默认为9600
    default:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    }

    newtio.c_cflag &= ~CSIZE;

    switch(this->serialdatabit)
    {
    case 5:
        newtio.c_cflag |= CS5;
        break;
    case 6:
        newtio.c_cflag |= CS6;
        break;
    case 7:
        newtio.c_cflag |= CS7;
        break;
    case 8:                                 // 默认为CS8
    default:
        newtio.c_cflag |= CS8;
        break;
    }

    switch(this->serialstopbit)
    {
    case 2:
        newtio.c_cflag |= CSTOPB;
	break;
    case 1:                                 // 默认为1
    default:
        newtio.c_cflag &= ~CSTOPB;
	break;
    }

    newtio.c_cflag &= ~PARENB;
    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN] = this->serialbufferlength;
    newtio.c_cflag |= CLOCAL | CREAD;
    tcflush(fd, TCIFLUSH);

    if((tcsetattr(fd, TCSANOW, &newtio)) != 0)
    {
        return false;
    }
    return true;
}

double SerialThread::SerialParseData(QString str)
{
    if(!str.isEmpty())
    {
        int offset_left = str.indexOf(this->serialdataseparate) + 1;
        int offset_right = str.indexOf(this->serialdataseparate, offset_left);
        QString midstr = str.mid(offset_left, offset_right - offset_left);
        if(midstr.length() <= this->serialdatavalidlength)
        {
            QString value;
            value.clear();
            for(int i = midstr.length() - 1; 0 <= i; i--)
            {
                value.append(midstr.at(i));
            }
            return value.toDouble() * 2;
        }
    }
    return 0.0;
}

void SerialThread::stop(void)
{
    qDebug() << "串口线程：终止运行";

    this->loop = false;
}

bool SerialThread::initSerial(QString &path, int rate, int databit, int stopbit, QString &separate, int validlen, int interval, int bufferlen)
{
    qDebug() << "串口线程：开始初始化参数";

    if(!INIConfig::safeVoluation(this->serialpath, path))
    {
        qCritical() << "串口线程：设置 this->serialpath 失败，传入的值为" << path;
        return false;
    }

    if(0 != access(this->serialpath.toLatin1().data(), F_OK))
    {
        qCritical() << "串口线程：设置 this->serialpath 失败，该设备地址不存在，传入的值为" << path;
        return false;
    }

    // TODO: 初始化并检查波特率
    this->serialrate = rate;
    switch(this->serialrate)
    {
    case 1200:
    case 1800:
    case 2400:
    case 4800:
    case 9600:
    case 19200:
    case 38400:
    case 57600:
    case 115200:
        break;
    default:
        qCritical() << "串口线程：波特率参数设置错误，请检查INI文件，返回主线程";
        return false;
    }
    
    // TODO: 初始化并检查数据位
    this->serialdatabit = databit;
    switch(this->serialdatabit)
    {
    case 5:
    case 6:
    case 7:
    case 8:
        break;
    default:
        qCritical() << "串口线程：数据位参数设置错误，请检查INI文件，返回主线程";
        return false;
    }

    // TODO: 初始化并检查停止位
    this->serialstopbit = stopbit;
    switch(this->serialstopbit)
    {
    case 1:
    case 2:
        break;
    default:
        qCritical() << "串口线程：停止位参数设置错误，请检查INI文件，返回主线程";
        return false;
    }

    this->serialdataseparate.clear();
    this->serialdataseparate = separate;
    if(this->serialdataseparate.isEmpty() || 1 < this->serialdataseparate.length())
    {
        qCritical() << "串口线程：分隔符参数设置错误，请检查INI文件，返回主线程";
        return false;
    }

    this->serialdatavalidlength = validlen;
    if(3 > this->serialdatavalidlength || 12 < this->serialdatavalidlength)
    {
        qCritical() << "串口线程：有效位参数设置错误，请检查INI文件，返回主线程";
        return false;
    }

    this->serialreadinterval = interval;
    if(0 > this->serialreadinterval || 5 < this->serialreadinterval)
    {
        qCritical() << "串口线程：有效位参数设置错误，请检查INI文件，返回主线程";
        return false;
    }

    this->serialbufferlength = bufferlen;
    if(0 > this->serialbufferlength || 255 < this->serialbufferlength)
    {
        qCritical() << "串口线程：缓冲区参数设置错误，请检查INI文件，返回主线程";
        return false;
    }

    // TODO: 初始化线程工作标志
    this->loop = true;

    qDebug() << "串口线程：参数初始化已经完成，返回主线程";
    return true;
}

bool SerialThread::isInitOK()
{
    qDebug() << "串口线程：当前运行状态为" << this->loop;
    return this->loop;
}

void SerialThread::run()
{
    int fd = 0;
    char buffer[1024] = {0};
    int nread = 0;

    if(!SerialThread::SerialOpenDevice(fd))
    {
        qDebug() << "串口线程：打开串口设备失败";
        emit this->Serial2UI_ReportFailSignal(1);
        return;
    }

    qDebug() << "串口线程：开始执行既定任务，当前运行状态为" << this->loop;

    while(this->loop)
    {
        tcflush(fd, TCIOFLUSH);
        nread = read(fd, buffer, sizeof(buffer));
        if(0 < nread)
        {
            if((signed)sizeof(buffer) > nread)
            {
                buffer[nread] = 0;
            }
            double val = this->SerialParseData(buffer);
            if(0.0 < val)
            {
                emit this->Serial2UI_ReportFailSignal(0);
                emit this->Serial2UI_UpdateValueSignal(val);
            }
            else
            {
                emit this->Serial2UI_ReportFailSignal(3);
            }
        }
        else
        {
            emit this->Serial2UI_ReportFailSignal(2);
        }
        if(0 < this->serialreadinterval)
        {
            QThread::sleep(this->serialreadinterval);
        }
    }
    close(fd);
    this->loop = true;
    qDebug() << "串口线程：已经终止";
}
